package com.icongyou.enterprise.talent_marking.controller;

import com.icongyou.enterprise.common.result.Result;
import com.icongyou.enterprise.talent_marking.entity.vo.ChangeDetailVO;
import com.icongyou.enterprise.talent_marking.entity.vo.ChangeItemVO;
import com.icongyou.enterprise.talent_marking.service.PerformanceChangesService;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
@DisplayName("绩效变化控制器测试")
class PerformanceChangesControllerTest {

    @Mock
    private PerformanceChangesService performanceChangesService;

    @InjectMocks
    private PerformanceChangesController controller;

    // ==================== getRecentChanges 测试 ====================

    @Test
    @DisplayName("获取最近变化 - 有数据")
    void testGetRecentChanges_WithData() {
        // Arrange
        ChangeDetailVO detail1 = createChangeDetail("STUDENT001", "张三", 2);
        ChangeDetailVO detail2 = createChangeDetail("STUDENT002", "李四", 1);

        List<ChangeDetailVO> changes = Arrays.asList(detail1, detail2);
        Result<List<ChangeDetailVO>> serviceResult = Result.success("发现2个课程的变化", changes);

        when(performanceChangesService.getRecentChanges()).thenReturn(serviceResult);

        // Act
        Result<List<ChangeDetailVO>> result = controller.getRecentChanges();

        // Assert
        assertEquals(200, result.getCode());
        assertEquals("发现2个课程的变化", result.getMessage());
        assertNotNull(result.getData());
        assertEquals(2, result.getData().size());

        verify(performanceChangesService).getRecentChanges();
    }

    @Test
    @DisplayName("获取最近变化 - 空列表")
    void testGetRecentChanges_EmptyList() {
        // Arrange
        Result<List<ChangeDetailVO>> serviceResult = 
                Result.success("发现0个课程的变化", Collections.emptyList());
        when(performanceChangesService.getRecentChanges()).thenReturn(serviceResult);

        // Act
        Result<List<ChangeDetailVO>> result = controller.getRecentChanges();

        // Assert
        assertEquals(200, result.getCode());
        assertNotNull(result.getData());
        assertTrue(result.getData().isEmpty());

        verify(performanceChangesService).getRecentChanges();
    }

    @Test
    @DisplayName("获取最近变化 - 单个学生多个变化")
    void testGetRecentChanges_SingleStudentMultipleChanges() {
        // Arrange
        ChangeDetailVO detail = createChangeDetail("STUDENT001", "张三", 3);

        List<ChangeDetailVO> changes = Arrays.asList(detail);
        Result<List<ChangeDetailVO>> serviceResult = Result.success("发现1个课程的变化", changes);

        when(performanceChangesService.getRecentChanges()).thenReturn(serviceResult);

        // Act
        Result<List<ChangeDetailVO>> result = controller.getRecentChanges();

        // Assert
        assertEquals(200, result.getCode());
        assertEquals(1, result.getData().size());

        ChangeDetailVO resultDetail = result.getData().get(0);
        assertEquals("STUDENT001", resultDetail.getStudentId());
        assertEquals("张三", resultDetail.getStudentName());
        assertEquals(3, resultDetail.getChanges().size());

        verify(performanceChangesService).getRecentChanges();
    }

    @Test
    @DisplayName("获取最近变化 - 验证变化详情完整性")
    void testGetRecentChanges_VerifyDetailCompleteness() {
        // Arrange
        ChangeDetailVO detail = new ChangeDetailVO();
        detail.setStudentId("STUDENT001");
        detail.setStudentName("张三");
        detail.setLatestChangeTime(new Date());

        ChangeItemVO item = new ChangeItemVO();
        item.setCourseId("COURSE001");
        item.setCourseName("Java编程");
        item.setChangeType("成绩变化");
        item.setChangeDescription("从80分变为85分");
        item.setDetectedTime(new Date());

        detail.setChanges(Arrays.asList(item));

        List<ChangeDetailVO> changes = Arrays.asList(detail);
        Result<List<ChangeDetailVO>> serviceResult = Result.success("发现1个课程的变化", changes);

        when(performanceChangesService.getRecentChanges()).thenReturn(serviceResult);

        // Act
        Result<List<ChangeDetailVO>> result = controller.getRecentChanges();

        // Assert
        ChangeDetailVO resultDetail = result.getData().get(0);
        assertNotNull(resultDetail.getLatestChangeTime());
        assertEquals(1, resultDetail.getChanges().size());

        ChangeItemVO resultItem = resultDetail.getChanges().get(0);
        assertEquals("COURSE001", resultItem.getCourseId());
        assertEquals("Java编程", resultItem.getCourseName());
        assertEquals("成绩变化", resultItem.getChangeType());
        assertEquals("从80分变为85分", resultItem.getChangeDescription());
        assertNotNull(resultItem.getDetectedTime());
    }

    @Test
    @DisplayName("获取最近变化 - 多个学生多种类型变化")
    void testGetRecentChanges_MultipleStudentsVariousChangeTypes() {
        // Arrange
        ChangeDetailVO detail1 = new ChangeDetailVO();
        detail1.setStudentId("STUDENT001");
        detail1.setStudentName("张三");

        ChangeItemVO scoreChange = new ChangeItemVO();
        scoreChange.setChangeType("成绩变化");
        scoreChange.setChangeDescription("成绩提升");

        ChangeItemVO rankChange = new ChangeItemVO();
        rankChange.setChangeType("排名变化");
        rankChange.setChangeDescription("排名上升");

        detail1.setChanges(Arrays.asList(scoreChange, rankChange));

        ChangeDetailVO detail2 = new ChangeDetailVO();
        detail2.setStudentId("STUDENT002");
        detail2.setStudentName("李四");

        ChangeItemVO progressChange = new ChangeItemVO();
        progressChange.setChangeType("进度变化");
        progressChange.setChangeDescription("完成新任务");

        detail2.setChanges(Arrays.asList(progressChange));

        List<ChangeDetailVO> changes = Arrays.asList(detail1, detail2);
        Result<List<ChangeDetailVO>> serviceResult = Result.success("发现2个课程的变化", changes);

        when(performanceChangesService.getRecentChanges()).thenReturn(serviceResult);

        // Act
        Result<List<ChangeDetailVO>> result = controller.getRecentChanges();

        // Assert
        assertEquals(2, result.getData().size());

        // 验证学生1有2种变化
        ChangeDetailVO s1 = result.getData().stream()
                .filter(d -> "STUDENT001".equals(d.getStudentId()))
                .findFirst()
                .orElse(null);
        assertNotNull(s1);
        assertEquals(2, s1.getChanges().size());

        // 验证学生2有1种变化
        ChangeDetailVO s2 = result.getData().stream()
                .filter(d -> "STUDENT002".equals(d.getStudentId()))
                .findFirst()
                .orElse(null);
        assertNotNull(s2);
        assertEquals(1, s2.getChanges().size());
    }

    @Test
    @DisplayName("获取最近变化 - 服务层调用一次")
    void testGetRecentChanges_ServiceCalledOnce() {
        // Arrange
        Result<List<ChangeDetailVO>> serviceResult = 
                Result.success("发现0个课程的变化", Collections.emptyList());
        when(performanceChangesService.getRecentChanges()).thenReturn(serviceResult);

        // Act
        controller.getRecentChanges();

        // Assert
        verify(performanceChangesService, times(1)).getRecentChanges();
    }

    @Test
    @DisplayName("获取最近变化 - 多次调用")
    void testGetRecentChanges_MultipleCalls() {
        // Arrange
        Result<List<ChangeDetailVO>> serviceResult = 
                Result.success(Collections.emptyList());
        when(performanceChangesService.getRecentChanges()).thenReturn(serviceResult);

        // Act
        controller.getRecentChanges();
        controller.getRecentChanges();
        controller.getRecentChanges();

        // Assert
        verify(performanceChangesService, times(3)).getRecentChanges();
    }

    @Test
    @DisplayName("获取最近变化 - 返回结果不为null")
    void testGetRecentChanges_ResultNotNull() {
        // Arrange
        Result<List<ChangeDetailVO>> serviceResult = Result.success(Collections.emptyList());
        when(performanceChangesService.getRecentChanges()).thenReturn(serviceResult);

        // Act
        Result<List<ChangeDetailVO>> result = controller.getRecentChanges();

        // Assert
        assertNotNull(result);
        assertNotNull(result.getData());
    }

    @Test
    @DisplayName("获取最近变化 - 包含不同变化类型")
    void testGetRecentChanges_DifferentChangeTypes() {
        // Arrange
        ChangeDetailVO detail = new ChangeDetailVO();
        detail.setStudentId("STUDENT001");
        detail.setStudentName("张三");

        List<ChangeItemVO> items = Arrays.asList(
            createChangeItem("COURSE001", "成绩变化", "成绩提升"),
            createChangeItem("COURSE002", "排名变化", "排名上升"),
            createChangeItem("COURSE003", "进度变化", "完成任务"),
            createChangeItem("COURSE004", "新任务分配", "分配新任务"),
            createChangeItem("COURSE005", "贡献度记录", "记录贡献度")
        );

        detail.setChanges(items);

        List<ChangeDetailVO> changes = Arrays.asList(detail);
        Result<List<ChangeDetailVO>> serviceResult = Result.success(changes);

        when(performanceChangesService.getRecentChanges()).thenReturn(serviceResult);

        // Act
        Result<List<ChangeDetailVO>> result = controller.getRecentChanges();

        // Assert
        ChangeDetailVO resultDetail = result.getData().get(0);
        assertEquals(5, resultDetail.getChanges().size());

        // 验证所有变化类型都存在
        List<String> changeTypes = resultDetail.getChanges().stream()
                .map(ChangeItemVO::getChangeType)
                .toList();

        assertTrue(changeTypes.contains("成绩变化"));
        assertTrue(changeTypes.contains("排名变化"));
        assertTrue(changeTypes.contains("进度变化"));
        assertTrue(changeTypes.contains("新任务分配"));
        assertTrue(changeTypes.contains("贡献度记录"));
    }

    // ==================== 辅助方法 ====================

    private ChangeDetailVO createChangeDetail(String studentId, String studentName, int changeCount) {
        ChangeDetailVO detail = new ChangeDetailVO();
        detail.setStudentId(studentId);
        detail.setStudentName(studentName);
        detail.setLatestChangeTime(new Date());

        List<ChangeItemVO> items = new ArrayList<>();
        for (int i = 0; i < changeCount; i++) {
            ChangeItemVO item = new ChangeItemVO();
            item.setCourseId("COURSE" + (i + 1));
            item.setCourseName("课程" + (i + 1));
            item.setChangeType("变化类型" + (i + 1));
            item.setChangeDescription("变化描述" + (i + 1));
            item.setDetectedTime(new Date());
            items.add(item);
        }

        detail.setChanges(items);
        return detail;
    }

    private ChangeItemVO createChangeItem(String courseId, String changeType, String description) {
        ChangeItemVO item = new ChangeItemVO();
        item.setCourseId(courseId);
        item.setCourseName("课程名称");
        item.setChangeType(changeType);
        item.setChangeDescription(description);
        item.setDetectedTime(new Date());
        return item;
    }
}
